#第七章 函数装饰器和闭包

#装饰器,装饰器在导入模块的时候就会被立即执行，被装饰函数则是在具体调用才执行

def decorate1(fn):
    def inner():
        print("inner....")
    return inner

def myFn():
    print("myFn..")

@decorate1
def myfn2():
    print("myfn2..")

myfn2() # myfn2是被装饰器装饰之后返回的函数内容 装饰器可以改变函数的行为

b = 6

def f(a):
    print(a)
    print(b) #单纯的打印是可以访问全局变量
    
f(3)

def f2(a):
    global b
    print('a=',a)    
    a = b + 2
    b = a + 1 #但是赋值的话 函数默认只会在函数体内搜索局部变量,要想访问全局变量需要添加global声明
    print("b",b)

f2(10)

#闭包

def make_avg(): #创建一个闭包函数 
    series = [] #这个变量会一直存在,其作用域会被延续
    def avg(val):
        series.append(val)
        total = sum(series)
        return total/len(series)
    return avg

avg = make_avg()

print(avg(10))
print(avg(12))
print(avg(14)) # 每次调用 函数内的 series 变量都一直存在

# 一个简单的装饰器 
'''

装饰器的行为:
把被装饰的函数替换成新函数，二者接受相同的参数，而且（通
常）返回被装饰的函数本该返回的值，同时还会做些额外操作。

'''
import time
import functools

def clocked(fn): #一个计算函数执行时长的装饰器
    @functools.wraps(fn) #把fn一些默认属性复制给inner函数
    def inner(*args):
        t0 = time.perf_counter()
        ret = fn(*args)
        t = time.perf_counter() - t0
        print(fn.__name__,"执行了%s"%t,"秒")
        return ret
    return inner

@clocked
def sleepFn():
    time.sleep(1)
    ary = []
    for i in range(0,10000):
        ary.append(i)

sleepFn()
